package cn.admin.configcenter.configservice.util;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;

public class MD5 {

	private static char[] digits = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
	private static Map<Character, Integer> rDigits = new HashMap<>(16);
	private static MD5 me = new MD5();
	private MessageDigest mHasher;
	private ReentrantLock opLock = new ReentrantLock();

	private MD5() {
		try {
			this.mHasher = MessageDigest.getInstance("md5");
		} catch (NoSuchAlgorithmException e) {
			throw new RuntimeException(e);
		}
	}

	public static MD5 getInstance() {
		return me;
	}

	public String getMD5String(String content) {
		return this.bytes2String(this.hash(content));
	}

	public String getMD5String(byte[] content) {
		return this.bytes2String(this.hash(content));
	}

	public byte[] getMD5Bytes(byte[] content) {
		return this.hash(content);
	}

	public byte[] hash(String str) {
		this.opLock.lock();
		byte[] result = null;
		try {
			byte[] bt = this.mHasher.digest(str.getBytes("GBK"));
			if (bt == null || bt.length != 16) {
				throw new IllegalArgumentException("md5 need");
			}
			result = bt;
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} finally {
			this.opLock.unlock();
		}
		return result;
	}

	public byte[] hash(byte[] data) {
		this.opLock.lock();
		byte[] result;
		try {
			byte[] bt = this.mHasher.digest(data);
			if (bt == null || bt.length != 16) {
				throw new IllegalArgumentException("md5 need");
			}
			result = bt;
		} finally {
			this.opLock.unlock();
		}
		return result;
	}

	public String bytes2String(byte[] bt) {
		int l = bt.length;
		char[] out = new char[l << 1];
		int i = 0;
		for (int j = 0;j < l;j ++) {
			out[j++] = digits[(240 & bt[i]) >>> 4];
			out[j++] = digits[15 & bt[i]];
		}
		return new String(out);
	}

	public byte[] string2bytes(String str) {
		if (null == str) {
			throw new NullPointerException("参数不能为空");
		} else if (str.length() != 32) {
			throw new IllegalArgumentException("字符串长度必须是32");
		} else {
			byte[] data = new byte[16];
			char[] chs = str.toCharArray();

			for(int i = 0; i < 16; ++i) {
				int h = rDigits.get(chs[i * 2]);
				int l = rDigits.get(chs[i * 2 + 1]);
				data[i] = (byte)((h & 15) << 4 | l & 15);
			}

			return data;
		}
	}

	static {
		for (int i = 0;i < digits.length;i ++) {
			rDigits.put(digits[i],i);
		}
	}

}
